package com.flyqiu.flow.core.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flyqiu.common.bean.FlyQiuBeanManage;
import com.flyqiu.common.tools.FlyQiuCollectionTools;
import com.flyqiu.flow.api.context.FlyQiuFlowGlobalContext;
import com.flyqiu.flow.api.service.FlowHistoryService;
import com.flyqiu.flow.api.service.IdentityLinkService;
import com.flyqiu.flow.api.service.base.FlowCommentService;
import com.flyqiu.flow.api.service.base.FlowVariableService;
import com.flyqiu.flow.event.ActInstEvent;
import com.flyqiu.flow.event.ProcInstEvent;
import com.flyqiu.flow.event.UserTaskEvent;
import com.flyqiu.flow.mapper.HiProcInstMapper;
import com.flyqiu.flow.mapper.HiUserTaskInstMapper;
import com.flyqiu.flow.mapper.ProcHiActivityMapper;
import com.flyqiu.flow.model.entity.Comment;
import com.flyqiu.flow.model.entity.base.Task;
import com.flyqiu.flow.model.entity.hi.ProcHiActivity;
import com.flyqiu.flow.model.entity.hi.ProcHiInst;
import com.flyqiu.flow.model.entity.hi.ProcHiUserTask;


import java.util.List;

public class FlowHistoryServiceImpl implements FlowHistoryService {
    private final FlyQiuFlowGlobalContext globalContext;

    private final ProcHiActivityMapper hiActivityMapper;
    private final HiProcInstMapper hiProcInstMapper;
    private final HiUserTaskInstMapper hiUserTaskInstMapper;

    private final FlowCommentService flowCommentService;

    private final FlowVariableService variableService;
    private final IdentityLinkService identityLinkService;


    public FlowHistoryServiceImpl(FlyQiuFlowGlobalContext globalContext,
                                  FlowCommentService flowCommentService,
                                  IdentityLinkService identityLinkService,
                                  FlowVariableService variableService
    ) {
        this.globalContext = globalContext;
        FlyQiuBeanManage procBean = globalContext.getBeanManage();
        hiProcInstMapper = procBean.getMapper(HiProcInstMapper.class);
        hiActivityMapper = procBean.getMapper(ProcHiActivityMapper.class);
        hiUserTaskInstMapper = procBean.getMapper(HiUserTaskInstMapper.class);
        this.flowCommentService = flowCommentService;
        this.variableService = variableService;
        this.identityLinkService = identityLinkService;
    }

    @Override
    public ProcHiInst getProcInst(String procInstId) {
        return hiProcInstMapper.selectById(procInstId);
    }

    /**
     * 分页查询流程实例
     *
     * @param page
     * @param queryWrapper
     * @return
     */
    @Override
    public Page<ProcHiInst> pageProcInst(Page<ProcHiInst> page, LambdaQueryWrapper<ProcHiInst> queryWrapper) {
        return hiProcInstMapper.selectPage(page, queryWrapper);
    }

    /**
     * 列表查询流程实例
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public List<ProcHiInst> listProcInst(LambdaQueryWrapper<ProcHiInst> queryWrapper) {
        return hiProcInstMapper.selectList(queryWrapper);
    }

    /**
     * 查询流程实例数量
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public long countProcInst(LambdaQueryWrapper<ProcHiInst> queryWrapper) {
        return hiProcInstMapper.selectCount(queryWrapper);
    }

    @Override
    public ProcHiUserTask getTask(String taskInstId) {
        return hiUserTaskInstMapper.selectById(taskInstId);
    }

    /**
     * 分页查询用户任务
     *
     * @param page
     * @param queryWrapper
     * @return
     */
    @Override
    public Page<ProcHiUserTask> pageTask(Page<ProcHiUserTask> page, LambdaQueryWrapper<ProcHiUserTask> queryWrapper) {
        return hiUserTaskInstMapper.selectPage(page, queryWrapper);
    }

    /**
     * 列表查询用户任务
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public List<ProcHiUserTask> listTask(LambdaQueryWrapper<ProcHiUserTask> queryWrapper) {
        return hiUserTaskInstMapper.selectList(queryWrapper);
    }

    /**
     * 查询任务数量
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public long countTask(LambdaQueryWrapper<ProcHiUserTask> queryWrapper) {
        return hiUserTaskInstMapper.selectCount(queryWrapper);
    }

    @Override
    public ProcHiActivity getActivity(String activityId) {
        return hiActivityMapper.selectById(activityId);
    }

    /**
     * 分页查询活动
     *
     * @param page
     * @param queryWrapper
     * @return
     */
    @Override
    public Page<ProcHiActivity> pageActivity(Page<ProcHiActivity> page, LambdaQueryWrapper<ProcHiActivity> queryWrapper) {
        return hiActivityMapper.selectPage(page, queryWrapper);
    }

    /**
     * 列表查询流程活动
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public List<ProcHiActivity> listActivity(LambdaQueryWrapper<ProcHiActivity> queryWrapper) {
        return hiActivityMapper.selectList(queryWrapper);
    }

    /**
     * 获取流程活动数量
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public long countActivity(LambdaQueryWrapper<ProcHiActivity> queryWrapper) {
        return hiActivityMapper.selectCount(queryWrapper);
    }

    /**
     * 分页查询备注信息
     *
     * @param page
     * @param lambdaQueryWrapper
     * @return
     */
    @Override
    public Page<Comment> pageComment(Page<Comment> page, LambdaQueryWrapper<Comment> lambdaQueryWrapper) {
        return flowCommentService.page(page, lambdaQueryWrapper);
    }

    /**
     * 列表查询备注信息
     *
     * @param lambdaQueryWrapper
     * @return
     */
    @Override
    public List<Comment> listComment(LambdaQueryWrapper<Comment> lambdaQueryWrapper) {
        return flowCommentService.list(lambdaQueryWrapper);
    }

    @Override
    public void deleteComment(LambdaQueryWrapper<Comment> queryWrapper) {
        flowCommentService.remove(queryWrapper);
    }

    /**
     * 获取备注数量
     *
     * @param lambdaQueryWrapper
     * @return
     */
    @Override
    public long countComment(LambdaQueryWrapper<Comment> lambdaQueryWrapper) {
        return flowCommentService.count(lambdaQueryWrapper);
    }

    @Override
    public void deleteProcInst(String procInstId, JSONObject params, String reason) {
        ProcHiInst procHiInst = hiProcInstMapper.selectById(procInstId);
        if (procHiInst == null) {
            return;
        }
        FlyQiuBeanManage procBean = globalContext.getBeanManage();
        globalContext.getTransactionManage().apply(() -> {
            globalContext.getFlowEventManage().triggerDeleteBeforeEvent(ProcInstEvent.class, procHiInst, params, reason);
            deleteSubProcInstByParentInstId(procBean, procInstId, params, reason);
            hiProcInstMapper.deleteById(procInstId);
            deleteTaskByProcInstId(procBean, procInstId, params, reason);
            deleteActivityByProcInstId(procBean, procInstId, params, reason);
            variableService.deleteHiVariable(procInstId);
            globalContext.getFlowEventManage().triggerDeleteAfterEvent(ProcInstEvent.class, procHiInst, params, reason);
        });
    }

    private void deleteTaskByProcInstId(FlyQiuBeanManage procBean, String procInstId, JSONObject params, String reason) {
        HiUserTaskInstMapper taskInstMapper = procBean.getMapper(HiUserTaskInstMapper.class);
        LambdaQueryWrapper<ProcHiUserTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Task::getProcInstId, procInstId);
        List<ProcHiUserTask> tasks = taskInstMapper.selectList(queryWrapper);
        FlyQiuCollectionTools.iterator(tasks, task -> {
            globalContext.getFlowEventManage().triggerDeleteBeforeEvent(UserTaskEvent.class, task, params, reason);

            globalContext.getFlowEventManage().triggerDeleteAfterEvent(UserTaskEvent.class, task, params, reason);
        });
        taskInstMapper.delete(queryWrapper);
    }

    private void deleteActivityByProcInstId(FlyQiuBeanManage procBean, String procInstId, JSONObject params, String reason) {
        ProcHiActivityMapper activityMapper = procBean.getMapper(ProcHiActivityMapper.class);
        LambdaQueryWrapper<ProcHiActivity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcHiActivity::getProcInstId, procInstId);
        List<ProcHiActivity> activities = activityMapper.selectList(queryWrapper);
        FlyQiuCollectionTools.iterator(activities, activity -> {
            globalContext.getFlowEventManage().triggerDeleteBeforeEvent(ActInstEvent.class, activity, params, reason);
            identityLinkService.deleteHiIdentityLink(activity.getId());
            variableService.deleteHiVariable(activity.getProcInstId(), activity.getId());
            flowCommentService.deleteComment(activity.getProcInstId(), activity.getId());
            globalContext.getFlowEventManage().triggerDeleteAfterEvent(ActInstEvent.class, activity, params, reason);
        });
        activityMapper.delete(queryWrapper);
    }

    private void deleteSubProcInstByParentInstId(FlyQiuBeanManage procBean, String procInstId, JSONObject params, String reason) {
        LambdaQueryWrapper<ProcHiInst> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcHiInst::getParentId, procInstId);
        List<ProcHiInst> insts = hiProcInstMapper.selectList(queryWrapper);
        if (FlyQiuCollectionTools.isEmpty(insts)) {
            return;
        }
        for (ProcHiInst subInst : insts) {
            deleteSubProcInstByParentInstId(procBean, subInst.getId(), params, reason);
            globalContext.getFlowEventManage().triggerDeleteBeforeEvent(ProcInstEvent.class, subInst, params, reason);
            deleteActivityByProcInstId(procBean, subInst.getId(), params, reason);
            deleteTaskByProcInstId(procBean, subInst.getId(), params, reason);
            variableService.deleteHiVariable(subInst.getId());
            globalContext.getFlowEventManage().triggerDeleteBeforeEvent(ProcInstEvent.class, subInst, params, reason);
        }
    }


}
